"""
文本编辑器组件
提供增强的文本编辑功能
"""

from PyQt6.QtWidgets import (QTextEdit, QWidget, QVBoxLayout, QHBoxLayout, 
                             QLabel, QScrollArea, QPlainTextEdit)
from PyQt6.QtCore import Qt, pyqtSignal, QRect, QSize
from PyQt6.QtGui import (QFont, QTextCursor, QSyntaxHighlighter, QTextCharFormat, 
                         QColor, QPainter, QTextFormat)


class LineNumberArea(QWidget):
    """行号显示区域"""
    
    def __init__(self, editor):
        super().__init__(editor)
        self.editor = editor
        
    def sizeHint(self):
        return QSize(self.editor.line_number_area_width(), 0)
    
    def paintEvent(self, event):
        self.editor.line_number_area_paint_event(event)


class TextEditor(QPlainTextEdit):
    """增强的文本编辑器，带行号显示"""
    
    text_changed = pyqtSignal()
    
    def __init__(self, parent=None):
        super().__init__(parent)
        self.line_number_area = LineNumberArea(self)
        self.setup_editor()
        self.setup_highlighter()
        
        # 连接信号
        self.blockCountChanged.connect(self.update_line_number_area_width)
        self.updateRequest.connect(self.update_line_number_area)
        self.cursorPositionChanged.connect(self.highlight_current_line)
        
        # 初始化
        self.update_line_number_area_width(0)
        self.highlight_current_line()
        
    def setup_editor(self):
        """设置编辑器"""
        # 设置字体
        font = QFont("Consolas", 10)
        self.setFont(font)
        
        # 设置行号显示
        self.setLineWrapMode(QPlainTextEdit.LineWrapMode.NoWrap)
        
        # 连接信号
        self.textChanged.connect(self.text_changed.emit)
        
        # 搜索相关
        self.search_text = ""
        self.replace_text = ""
        self.case_sensitive = False
        self.whole_word = False
        self.current_highlight = None
        
    def setup_highlighter(self):
        """设置语法高亮"""
        self.highlighter = BasicHighlighter(self.document())
    
    def line_number_area_width(self):
        """计算行号区域宽度"""
        digits = 1
        max_num = max(1, self.blockCount())
        while max_num >= 10:
            max_num //= 10
            digits += 1
        
        space = 3 + self.fontMetrics().horizontalAdvance('9') * digits
        return space
    
    def update_line_number_area_width(self, _):
        """更新行号区域宽度"""
        self.setViewportMargins(self.line_number_area_width(), 0, 0, 0)
    
    def update_line_number_area(self, rect, dy):
        """更新行号区域"""
        if dy:
            self.line_number_area.scroll(0, dy)
        else:
            self.line_number_area.update(0, rect.y(), self.line_number_area.width(), rect.height())
        
        if rect.contains(self.viewport().rect()):
            self.update_line_number_area_width(0)
    
    def resizeEvent(self, event):
        """重写大小改变事件"""
        super().resizeEvent(event)
        
        cr = self.contentsRect()
        self.line_number_area.setGeometry(QRect(cr.left(), cr.top(),
                                               self.line_number_area_width(), cr.height()))
    
    def line_number_area_paint_event(self, event):
        """绘制行号区域"""
        painter = QPainter(self.line_number_area)
        painter.fillRect(event.rect(), QColor("#f0f0f0"))
        
        block = self.firstVisibleBlock()
        block_number = block.blockNumber()
        top = self.blockBoundingGeometry(block).translated(self.contentOffset()).top()
        bottom = top + self.blockBoundingRect(block).height()
        
        while block.isValid() and top <= event.rect().bottom():
            if block.isVisible() and bottom >= event.rect().top():
                number = str(block_number + 1)
                painter.setPen(QColor("#666666"))
                painter.drawText(QRect(0, int(top), self.line_number_area.width() - 5, 
                               self.fontMetrics().height()),
                               Qt.AlignmentFlag.AlignRight, number)
            
            block = block.next()
            top = bottom
            bottom = top + self.blockBoundingRect(block).height()
            block_number += 1
    
    def highlight_current_line(self):
        """高亮当前行"""
        extra_selections = []
        
        if not self.isReadOnly():
            selection = QTextEdit.ExtraSelection()
            
            line_color = QColor(Qt.GlobalColor.yellow).lighter(160)
            selection.format.setBackground(line_color)
            selection.format.setProperty(QTextFormat.Property.FullWidthSelection, True)
            selection.cursor = self.textCursor()
            selection.cursor.clearSelection()
            extra_selections.append(selection)
        
        self.setExtraSelections(extra_selections)
    
    def get_text_statistics(self):
        """获取文本统计信息"""
        text = self.toPlainText()
        lines = text.split('\n')
        
        stats = {
            'characters': len(text),
            'characters_no_spaces': len(text.replace(' ', '').replace('\n', '')),
            'words': len(text.split()),
            'lines': len(lines),
            'non_empty_lines': len([line for line in lines if line.strip()]),
            'paragraphs': len([p for p in text.split('\n\n') if p.strip()])
        }
        
        return stats
    
    def find_text(self, search_text, case_sensitive=False, whole_word=False):
        """查找文本"""
        cursor = self.textCursor()
        cursor.clearSelection()
        
        flags = QTextCursor.MoveOperation.NoMove
        if case_sensitive:
            flags |= QTextCursor.MoveOperation.KeepAnchor
        
        # 查找文本
        found = self.find(search_text, flags)
        if found:
            self.setTextCursor(cursor)
            return True
        return False
    
    def replace_text(self, search_text, replace_text, case_sensitive=False, whole_word=False):
        """替换文本"""
        cursor = self.textCursor()
        if cursor.hasSelection() and cursor.selectedText() == search_text:
            cursor.insertText(replace_text)
            return True
        return False
    
    def replace_all(self, search_text, replace_text, case_sensitive=False, whole_word=False):
        """替换所有匹配的文本"""
        cursor = self.textCursor()
        cursor.movePosition(QTextCursor.MoveOperation.Start)
        self.setTextCursor(cursor)
        
        count = 0
        while self.find(search_text):
            cursor = self.textCursor()
            cursor.insertText(replace_text)
            count += 1
        
        return count
    
    def go_to_line(self, line_number):
        """跳转到指定行"""
        text = self.toPlainText()
        lines = text.split('\n')
        
        if 1 <= line_number <= len(lines):
            # 计算目标位置
            position = 0
            for i in range(line_number - 1):
                position += len(lines[i]) + 1  # +1 for newline
            
            cursor = self.textCursor()
            cursor.setPosition(position)
            self.setTextCursor(cursor)
            self.ensureCursorVisible()
            return True
        return False
    
    def duplicate_line(self):
        """复制当前行"""
        cursor = self.textCursor()
        cursor.select(QTextCursor.SelectionType.LineUnderCursor)
        selected_text = cursor.selectedText()
        
        if selected_text:
            cursor.movePosition(QTextCursor.MoveOperation.EndOfLine)
            cursor.insertText('\n' + selected_text)
    
    def delete_line(self):
        """删除当前行"""
        cursor = self.textCursor()
        cursor.select(QTextCursor.SelectionType.LineUnderCursor)
        cursor.removeSelectedText()
        cursor.deleteChar()  # 删除换行符
    
    def comment_line(self, comment_char='#'):
        """注释/取消注释当前行"""
        cursor = self.textCursor()
        cursor.select(QTextCursor.SelectionType.LineUnderCursor)
        selected_text = cursor.selectedText()
        
        if selected_text.startswith(comment_char + ' '):
            # 取消注释
            uncommented = selected_text[len(comment_char) + 1:]
            cursor.insertText(uncommented)
        else:
            # 添加注释
            commented = comment_char + ' ' + selected_text
            cursor.insertText(commented)
    
    def indent_selection(self, spaces=4):
        """缩进选中的文本"""
        cursor = self.textCursor()
        if cursor.hasSelection():
            selected_text = cursor.selectedText()
            lines = selected_text.split('\n')
            indented_lines = [' ' * spaces + line for line in lines]
            cursor.insertText('\n'.join(indented_lines))
    
    def unindent_selection(self, spaces=4):
        """取消缩进选中的文本"""
        cursor = self.textCursor()
        if cursor.hasSelection():
            selected_text = cursor.selectedText()
            lines = selected_text.split('\n')
            unindented_lines = []
            for line in lines:
                if line.startswith(' ' * spaces):
                    unindented_lines.append(line[spaces:])
                else:
                    unindented_lines.append(line)
            cursor.insertText('\n'.join(unindented_lines))
    
    def insert_text_at_cursor(self, text):
        """在光标位置插入文本"""
        cursor = self.textCursor()
        cursor.insertText(text)
    
    def get_selected_text(self):
        """获取选中的文本"""
        cursor = self.textCursor()
        return cursor.selectedText()
    
    def has_selection(self):
        """是否有选中的文本"""
        cursor = self.textCursor()
        return cursor.hasSelection()
    
    def select_all_text(self):
        """选择所有文本"""
        cursor = self.textCursor()
        cursor.movePosition(QTextCursor.MoveOperation.Start)
        cursor.movePosition(QTextCursor.MoveOperation.End, QTextCursor.MoveMode.KeepAnchor)
        self.setTextCursor(cursor)
    
    def get_current_line_number(self):
        """获取当前行号"""
        cursor = self.textCursor()
        text = self.toPlainText()
        position = cursor.position()
        
        lines = text[:position].split('\n')
        return len(lines)
    
    def get_total_lines(self):
        """获取总行数"""
        text = self.toPlainText()
        return len(text.split('\n'))
    
    def find_text(self, search_text, case_sensitive=False, whole_word=False, forward=True):
        """查找文本"""
        if not search_text:
            return False
            
        cursor = self.textCursor()
        flags = QTextCursor.MoveOperation.NoMove
        
        if not forward:
            flags |= QTextCursor.MoveOperation.Backward
            
        if case_sensitive:
            flags |= QTextCursor.MoveOperation.KeepAnchor
            
        # 清除之前的搜索高亮
        self.clear_search_highlights()
        
        # 执行搜索
        found = self.find(search_text, flags)
        if found:
            # 高亮搜索结果
            self.highlight_search_result(cursor)
            return True
        return False
    
    def find_all(self, search_text, case_sensitive=False, whole_word=False):
        """查找所有匹配项"""
        if not search_text:
            return []
            
        self.search_text = search_text
        self.case_sensitive = case_sensitive
        self.whole_word = whole_word
        
        # 清除之前的搜索高亮
        self.clear_search_highlights()
        
        # 查找所有匹配项
        matches = []
        cursor = self.textCursor()
        cursor.movePosition(QTextCursor.MoveOperation.Start)
        self.setTextCursor(cursor)
        
        while self.find(search_text):
            cursor = self.textCursor()
            matches.append({
                'position': cursor.position(),
                'selected_text': cursor.selectedText(),
                'line': cursor.blockNumber() + 1
            })
        
        # 高亮所有搜索结果
        self.highlight_all_search_results(matches)
        
        return matches
    
    def replace_text(self, search_text, replace_text, case_sensitive=False, whole_word=False):
        """替换当前选中的文本"""
        cursor = self.textCursor()
        if cursor.hasSelection() and cursor.selectedText() == search_text:
            cursor.insertText(replace_text)
            return True
        return False
    
    def replace_all(self, search_text, replace_text, case_sensitive=False, whole_word=False):
        """替换所有匹配的文本"""
        if not search_text:
            return 0
            
        cursor = self.textCursor()
        cursor.movePosition(QTextCursor.MoveOperation.Start)
        self.setTextCursor(cursor)
        
        count = 0
        while self.find(search_text):
            cursor = self.textCursor()
            cursor.insertText(replace_text)
            count += 1
        
        return count
    
    def highlight_search_result(self, cursor):
        """高亮当前搜索结果"""
        if self.current_highlight:
            self.current_highlight.format.setBackground(QColor("#ffff00"))
            self.current_highlight.format.setForeground(QColor("#000000"))
        
        # 创建新的高亮
        highlight = QTextEdit.ExtraSelection()
        highlight.cursor = cursor
        highlight.format.setBackground(QColor("#ffeb3b"))
        highlight.format.setForeground(QColor("#000000"))
        
        self.current_highlight = highlight
        self.setExtraSelections([highlight])
    
    def highlight_all_search_results(self, matches):
        """高亮所有搜索结果"""
        extra_selections = []
        
        for match in matches:
            cursor = QTextCursor(self.document())
            cursor.setPosition(match['position'])
            cursor.setPosition(match['position'] + len(match['selected_text']), 
                             QTextCursor.MoveMode.KeepAnchor)
            
            highlight = QTextEdit.ExtraSelection()
            highlight.cursor = cursor
            highlight.format.setBackground(QColor("#fff59d"))
            highlight.format.setForeground(QColor("#000000"))
            
            extra_selections.append(highlight)
        
        self.setExtraSelections(extra_selections)
    
    def clear_search_highlights(self):
        """清除搜索高亮"""
        self.current_highlight = None
        self.setExtraSelections([])
    
    def get_search_info(self):
        """获取搜索信息"""
        if not self.search_text:
            return "未搜索"
        
        text = self.toPlainText()
        if self.case_sensitive:
            count = text.count(self.search_text)
        else:
            count = text.lower().count(self.search_text.lower())
        
        return f"找到 {count} 个匹配项"


class BasicHighlighter(QSyntaxHighlighter):
    """基础语法高亮器"""
    
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setup_formats()
    
    def setup_formats(self):
        """设置格式"""
        # 关键字格式
        self.keyword_format = QTextCharFormat()
        self.keyword_format.setForeground(QColor("#FF6B6B"))
        self.keyword_format.setFontWeight(QFont.Weight.Bold)
        
        # 字符串格式
        self.string_format = QTextCharFormat()
        self.string_format.setForeground(QColor("#4ECDC4"))
        
        # 注释格式
        self.comment_format = QTextCharFormat()
        self.comment_format.setForeground(QColor("#95A5A6"))
        self.comment_format.setFontItalic(True)
        
        # 数字格式
        self.number_format = QTextCharFormat()
        self.number_format.setForeground(QColor("#F39C12"))
    
    def highlightBlock(self, text):
        """高亮文本块"""
        # 高亮关键字
        keywords = [
            'def', 'class', 'import', 'from', 'as', 'if', 'else', 'elif',
            'for', 'while', 'try', 'except', 'finally', 'with', 'return',
            'True', 'False', 'None', 'self', 'super', 'lambda', 'yield',
            'function', 'var', 'let', 'const', 'if', 'else', 'for', 'while',
            'try', 'catch', 'finally', 'return', 'break', 'continue'
        ]
        
        for keyword in keywords:
            import re
            pattern = r'\b' + re.escape(keyword) + r'\b'
            for match in re.finditer(pattern, text, re.IGNORECASE):
                self.setFormat(match.start(), match.end() - match.start(), self.keyword_format)
        
        # 高亮字符串
        import re
        string_pattern = r'"[^"]*"|\'[^\']*\''
        for match in re.finditer(string_pattern, text):
            self.setFormat(match.start(), match.end() - match.start(), self.string_format)
        
        # 高亮注释
        comment_pattern = r'#.*$'
        for match in re.finditer(comment_pattern, text):
            self.setFormat(match.start(), match.end() - match.start(), self.comment_format)
        
        # 高亮数字
        number_pattern = r'\b\d+\b'
        for match in re.finditer(number_pattern, text):
            self.setFormat(match.start(), match.end() - match.start(), self.number_format) 